<?php


namespace app\reception\controller;


use app\backstage\model\KlOrder;
use app\backstage\model\Order;
use app\common\model\PaymentNumber;
use app\common\model\QuickUser;
use app\common\model\UserBookPoints;
use app\reception\classs\FuyouHelp;
use app\reception\logic\LogLogic;
use app\reception\server\MiHuaPayServer;
use think\Db;
use Yansongda\Pay\Pay;

/**
 * 回调通知
 * Class Notify
 * @package app\reception\controller
 */
class Notify
{

    /**
     * 原生回调
     * @return \Symfony\Component\HttpFoundation\Response
     * @throws \Yansongda\Pay\Exceptions\InvalidArgumentException
     * @throws \Yansongda\Pay\Exceptions\InvalidSignException
     */
    public function weChatNative()
    {
        $payId = input('payId');
        $wxConfig = [
            'appid' => '', // APP APPID
            'app_id' => '', // 公众号 APPID
            'miniapp_id' => '', // 小程序 APPID
            'mch_id' => '',
            'key' => '',
            'notify_url' => '',
            'cert_client' => '', // optional, 退款，红包等情况时需要用到
            'cert_key' => '',// optional, 退款，红包等情况时需要用到
            'log' => [ // optional
                'file' => './logs/wechat.log',
                'level' => 'info', // 建议生产环境等级调整为 info，开发环境为 debug
                'type' => 'single', // optional, 可选 daily.
                'max_file' => 30, // optional, 当 type 为 daily 时有效，默认 30 天
            ],
            'http' => [ // optional
                'timeout' => 5.0,
                'connect_timeout' => 5.0,
                // 更多配置项请参考 [Guzzle](https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html)
            ]
        ];
        $paymentNumber = PaymentNumber::get($payId);
        if (!$paymentNumber) {
            echo "paymentNumber error";
            die;
        }
        if ($paymentNumber['pay_style'] == 1) {
            $wxConfig['app_id'] = $paymentNumber['app_id'];
        } else {
            $wxConfig['appid'] = $paymentNumber['app_id'];//未尝试
        }
        $wxConfig['mch_id'] = $paymentNumber['mch_id'];
        $wxConfig['key'] = $paymentNumber['apiv3'];
        $wechat = Pay::wechat($wxConfig);
        $result = $wechat->verify();
        $result = json_decode($result, true);
        $where[] = ['out_trade_no', '=', $result['out_trade_no']];
        $where[] = ['status', '=', 1];
        $oat = $this->getOrderAndTable($where);
        $order = $oat['order'];
        if (!$order){
            echo "order error";die;
        }
        $user = QuickUser::where("id", $order->uid)->findOrFail();
        if ($result['result_code'] == 'SUCCESS') {
            if ($oat['channel'] == 'zc') {
                $res = $this->orderHand($order, $user, $result['transaction_id']);
            }else{
                $res = $this->klOrderHand($order, $user, $result['transaction_id']);
            }
            if ($res) {
                return $wechat->success()->send();
            }
        }
    }


    /**
     * 查找订单
     * @param $where
     * @return mixed
     */
    private function getOrderAndTable($where)
    {
        $data['channel'] = 'zc';
        $data['order'] = Order::where($where)->find();
        if (!$data['order']) {
            $data['order'] = KlOrder::where($where)->find();
            if ($data['order']) {
                $data['channel'] = 'kl';
            }
        }
        return $data;
    }


    /**
     * 米花回调
     */
    public function miHua()
    {
        libxml_disable_entity_loader(true);
        $param = request()->param();
        $merAccount = $param['merAccount'];
        $encodeData = $param['data'];
        $orderId = $param['orderId'];
        if (!$merAccount) {
            die('401');
        }
        $paymentNumber = PaymentNumber::where("mer_account", $merAccount)->where("payment_type", 2)->findOrFail();
        $server = new MiHuaPayServer();
        $decryptData = $server->newMhCheckSign($encodeData, $paymentNumber);
        if (empty($decryptData) || $decryptData['orderStatus'] != 'SUCCESS') {
            die('401');
        }
        // 订单解密
        $orderData = $server->newMhGetOrder($decryptData, $paymentNumber);
        if ($orderData['code'] != '000000') {
            die('402');
        }
        $result = $orderData['data']; // 微信支付订单号
        $where[] = ['out_trade_no', '=', $result['orderId']];
        $where[] = ['status', '=', 1];
        $oat = $this->getOrderAndTable($where);
        $order = $oat['order'];
        if (!$order){
            header("Content-type: text/html; charset=utf-8");
            echo 'SUCCESS';
            exit;
        }
        $user = QuickUser::where("id", $order->uid)->findOrFail();
        if ($oat['channel'] == 'zc'){
            $res = $this->orderHand($order, $user, $result['mbOrderId']);
        }else{
            $res = $this->klOrderHand($order, $user, $result['mbOrderId']);
        }
        if ($res) {
            header("Content-type: text/html; charset=utf-8");
            echo 'SUCCESS';
            exit;
        }
    }


    /**
     * 原生支付宝回调
     * @return \Symfony\Component\HttpFoundation\Response
     * @throws \Yansongda\Pay\Exceptions\InvalidConfigException
     * @throws \Yansongda\Pay\Exceptions\InvalidSignException
     */
    public function aliNative()
    {
        $payId = input('payId');
        $zfbConfig = [
            'app_id' => '',
            'notify_url' => '',
            'return_url' => '',
            'ali_public_key' => '',
            'private_key' => '',
            'log' => [ // optional
                'file' => './logs/alipay.log',
                'level' => 'info', // 建议生产环境等级调整为 info，开发环境为 debug
                'type' => 'single', // optional, 可选 daily.
                'max_file' => 30, // optional, 当 type 为 daily 时有效，默认 30 天
            ],
            'http' => [ // optional
                'timeout' => 5.0,
                'connect_timeout' => 5.0,
                // 更多配置项请参考 [Guzzle](https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html)
            ],
            // 'mode' => 'dev', // optional,设置此参数，将进入沙箱模式
        ];
        $paymentNumber = PaymentNumber::get($payId);
        if (!$paymentNumber) {
            echo "paymentNumber error";
            die;
        }
        $zfbConfig['app_id'] = $paymentNumber['app_id'];
        $zfbConfig['ali_public_key'] = $paymentNumber['public_key'];
        $zfbConfig['private_key'] = $paymentNumber['private_key'];
        $alipay = Pay::alipay($zfbConfig);
        $result = $alipay->verify();
        $result = json_decode($result, true);
        $where[] = ['out_trade_no', '=', $result['out_trade_no']];
        $where[] = ['status', '=', 1];
        $oat = $this->getOrderAndTable($where);
        $order = $oat['order'];
        if (!$order){
            echo "order error";
            die;
        }
        $user = QuickUser::where("id", $order->uid)->findOrFail();
        if ($result['trade_status'] == 'TRADE_SUCCESS') {
            if ($oat['channel'] == 'zc') {
                $res = $this->orderHand($order, $user, $result['trade_no']);
            }else{
                $res = $this->klOrderHand($order, $user, $result['trade_no']);
            }
            if ($res) {
                return $alipay->success()->send();
            }
        }
    }

    /**
     * 富友回调
     */
    public function fuYou()
    {
        $data = file_get_contents("php://input");
        if ($data) {
            $data = json_decode($data, true);
            if ($data['resp_code'] == '0000') {
                $paymentNumber = PaymentNumber::where("mer_no", $data['mchnt_cd'])->where("payment_type", 3)->findOrFail();
                $fyHelp = new FuyouHelp($paymentNumber['public_key'], $paymentNumber['private_key']);
                $message = $fyHelp->privateDecryptRsa($data['message']);
                $message = json_decode($message, true);
                $out_trade_no = $message['order_id'];
                $where[] = ['out_trade_no', '=', $out_trade_no];
                $where[] = ['status', '=', 1];
                $oat = $this->getOrderAndTable($where);
                $order = $oat['order'];
                if (!$order){
                    echo "order error";
                    die;
                }
                $user = QuickUser::where("id", $order->uid)->findOrFail();
                if ($message['order_st'] == 1) {
                    if ($oat['channel'] == 'zc') {
                        $res = $this->orderHand($order, $user, $message['pay_ssn']);
                    }else{
                        $res = $this->klOrderHand($order, $user, $message['pay_ssn']);
                    }
                    if ($res) {
                        echo 'SUCCESS';
                        exit;
                    } else {
                        echo 'FAIL';
                        exit;
                    }
                }
            }
        }
    }


    /**
     * 订单处理
     * @param $order
     * @param $user
     * @param $tradeNo
     * @return bool
     */
    private function orderHand($order, $user, $tradeNo)
    {
        if($order['status'] == 2)
        {
            //订单已支付无需重复处理
            return true;
        }
        $data_success =  $order->toArray();
        $data_success['order_id'] = $order->id;
        unset($data_success['id']);

        $virtual_currency = $order->virtual_currency;
        $point_gift = $order->point_gift;
        $vipdays = $order->vipdays;

        Db::startTrans();
        try {
            if ($point_gift > 0) {
                $ubp = new UserBookPoints();
                $ubp->givePoint($user->id, $point_gift, $ubp::payment);
            }
            if ($virtual_currency > 0) {
                Db::table(QuickUser::fbTable($user->quick_id))->where('id', $user->id)->setInc('book_coin', $virtual_currency);
                Db::table('quick_user')->where('id', $user->id)->setInc('book_coin', $virtual_currency);
            }
            if ($vipdays > 0) {
                $time = time();
                if ($user->vip_exp_time > $time) {
                    $vip_exp_time = $user->vip_exp_time + $vipdays * 86400;
                } else {
                    $vip_exp_time = $time + $vipdays * 86400;
                }
                Db::table(QuickUser::fbTable($user->quick_id))->where('id', $user->id)->setField('vip_exp_time', $vip_exp_time);
                Db::table('quick_user')->where('id', $user->id)->setField('vip_exp_time', $vip_exp_time);
            }
            Db::table(QuickUser::fbTable($user->quick_id))->where('id', $user->id)->setInc('pay_times');
            Db::table('quick_user')->where('id', $user->id)->setInc('pay_times');
            Db::table(QuickUser::fbTable($user->quick_id))->where('id', $user->id)->setInc('pay_money', $order->total_fee);
            Db::table('quick_user')->where('id', $user->id)->setInc('pay_money', $order->total_fee);
            $this->refProtectDay($order->quick_id, $user->id);//更新保护期
            $uoWhere[] = ['uid', '=', $user->id];
            $uoWhere[] = ['status', '=', 2];
            $payCount = Db::table("pay_order")->where($uoWhere)->count();
            $pay_time = time();
            Db::table("pay_order")->where("id", $order->id)->update([
                'status'            => 2,
                'pay_time'          => $pay_time,
                'recharge_times'    => $payCount + 1,
                'trade_no'          => $tradeNo
            ]);

            $data_success['trade_no']       = $tradeNo;
            $data_success['recharge_times'] = $payCount + 1;
            $data_success['pay_time']       = $pay_time;
            $data_success['status']         = 2;

            Db::table("pay_order_success")->insert($data_success);

            //书籍充值次数
            if ($order->nid > 0) {
                $flag = Db::table("rp_novel_recharge_repeat_detail")->where("nid", $order->nid)->where("uid", $order->uid)->find();
                if (!$flag) {
                    Db::table("rp_novel_recharge_repeat_detail")->insert([
                        'qid' => $order->quick_id,
                        'nid' => $order->nid,
                        'uid' => $order->uid,
                        'pay_count' => 1,
                    ]);
                } else {
                    Db::table("rp_novel_recharge_repeat_detail")->where("nid", $order->nid)->where("uid", $order->uid)->setInc('pay_count');
                }
            }
            //真实用户充值信息
            $payRecord = Db::table("quick_pay_user_record")->where("uid", $user->id)->find();
            if ($payRecord) {
                Db::table("quick_pay_user_record")->where("uid", $user->id)->setInc('pay_money', $order->total_fee);
                Db::table("quick_pay_user_record")->where("uid", $user->id)->setInc('pay_num');
            } else {
                Db::table("quick_pay_user_record")->insert([
                    'uid' => $user->id,
                    'pay_money' => $order->total_fee,
                    'pay_num' => 1,
                ]);
            }
            Db::commit();
            return true;
        } catch (\Exception $e) {
            Db::rollback();
            LogLogic::addLog('orderHand', "paymentId:{$order->chargefrom},msg:{$e->getMessage()},line:{$e->getLine()}}", $user->id, $order->quick_id);
            return false;
        }
    }




    /**
     * 订单处理
     * @param $order
     * @param $user
     * @param $tradeNo
     * @return bool
     */
    private function klOrderHand($order, $user, $tradeNo)
    {
        if($order['status'] == 2)
        {
            //订单已支付无需重复处理
            return true;
        }
        $data_success =  $order->toArray();
        $data_success['order_id'] = $order->id;
        unset($data_success['id']);

        $virtual_currency = $order->virtual_currency;
        $point_gift = $order->point_gift;
        $vipdays = $order->vipdays;

        Db::startTrans();
        try {
            if ($point_gift > 0) {
                $ubp = new UserBookPoints();
                $ubp->givePoint($user->id, $point_gift, $ubp::payment);
            }
            if ($virtual_currency > 0) {
                Db::table(QuickUser::fbTable($user->quick_id))->where('id', $user->id)->setInc('book_coin', $virtual_currency);
                Db::table('quick_user')->where('id', $user->id)->setInc('book_coin', $virtual_currency);
            }
            if ($vipdays > 0) {
                $time = time();
                if ($user->vip_exp_time > $time) {
                    $vip_exp_time = $user->vip_exp_time + $vipdays * 86400;
                } else {
                    $vip_exp_time = $time + $vipdays * 86400;
                }
                Db::table(QuickUser::fbTable($user->quick_id))->where('id', $user->id)->setField('vip_exp_time', $vip_exp_time);
                Db::table('quick_user')->where('id', $user->id)->setField('vip_exp_time', $vip_exp_time);
            }
            $this->refProtectDay($order->quick_id, $user->id);//更新保护期
            $uoWhere[] = ['uid', '=', $user->id];
            $uoWhere[] = ['status', '=', 2];
            $payCount = Db::table("pay_order_kl_backups")->where($uoWhere)->count();
            $pay_time = time();
            Db::table("pay_order_kl_backups")->where("id", $order->id)->update([
                'status'            => 2,
                'pay_time'          => $pay_time,
                'recharge_times'    => $payCount + 1,
                'trade_no'          => $tradeNo
            ]);
            $klUser = Db::table("pay_order_kl_user")->where("uid", $user->id)->find();
            if (!$klUser) {
                Db::table("pay_order_kl_user")->insert([
                    'uid' => $user->id
                ]);
            }
            $allTotalFee = Db::table("pay_order_kl_backups")->where("channel_id", $order->channel_id)->where("status", 2)->sum('total_fee') ?? 0;
            Db::table("pay_order_kl_config")->where("channel_id", $order->channel_id)->setField('money', $allTotalFee);
            Db::commit();
            return true;
        } catch (\Exception $e) {
            Db::rollback();
            LogLogic::addLog('klOrderHand', "paymentId:{$order->chargefrom},msg:{$e->getMessage()},line:{$e->getLine()}}", $user->id, $order->quick_id);
            return false;
        }
    }


    /**
     * 更新保护器
     * @param $quickId
     * @param $uid
     */
    private function refProtectDay($quickId, $uid)
    {
        $protectDay = Db::table("quick_app_info")->where("quick_id", $quickId)->value('protect_day');
        if ($protectDay) {
            $currentDate = date('Y-m-d H:i:s');
            $sevenDaysLater = strtotime("+{$protectDay} days", strtotime($currentDate));
            $exp_time = date('Y-m-d H:i:s', $sevenDaysLater);
            Db::table('quick_user')->where('id', $uid)->setField('exp_time', $exp_time);
            Db::table(QuickUser::fbTable($quickId))->where('id', $uid)->setField('exp_time', $exp_time);
        }
    }
}